package com.hly.tool.log;


import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.text.MessageFormat;

/**
 * @author ：Jack Hao
 * @date ：Created in 2021/6/18 15:36
 * @description：JDK9及JDK9以上版本使用
 */
public class EnoviaLogger
{

//    tackDepth 栈深（下标） 2：调用者类信息
    private static final int stackDepth = 3;

    /**
     * 空数组
     */
    private static final Object[] EMPTY_ARRAY = new Object[]{};
    /**
     * 全类名
     */
    private static final String FQCN = EnoviaLogger.class.getName();

    /**
     * logback 的配置文件 固定为logback-ky-tool.xml
     * 获取栈中类信息
     *
     * @return org.slf4j.spi.LocationAwareLogger
     */
    private static LocationAwareLogger getLocationAwareLogger()
    {
        /**通过堆栈信息获取调用当前方法的类名和方法名*/

        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(lc);
        lc.reset();
        try
        {
            //getResource()方法会去classpath下找这个文件，获取到url resource, 得到这个资源后，调用url.getFile获取到 文件 的绝对路径
            ClassLoader classLoader = EnoviaLogger.class.getClassLoader();
            URL url = classLoader.getResource("logback-ky-tool.xml");

            //设定logback 配置文件
            configurator.doConfigure(url.getFile());
        } catch (JoranException e)
        {
            e.printStackTrace();
        }
//        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);

        // <= JDK8
//        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
//        Throwable throwable = new Throwable();
//        JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
//        StackTraceElement frame = access.getStackTraceElement(throwable, stackDepth);

        // >=JDK9
        String invonkingClassName = getInvonkingClassName(true);

        LocationAwareLogger logger = (LocationAwareLogger) LoggerFactory.getLogger(invonkingClassName);


        return logger;
    }


    /**
     * 获取当前class的名称
     * @param fullClassNameNeeded
     * @return
     */
    public static String getInvonkingClassName(boolean fullClassNameNeeded ){

        StackTraceElement[] stack = new Exception().getStackTrace();

        String className = stack[stackDepth].getClassName();
        if(!fullClassNameNeeded){
            int idx = className.lastIndexOf('.');
            className = className.substring(idx+1);
        }

        int index = className.indexOf("_mxJPO");
        if(index>0){
            className = className.substring(0,index+6);
        }

        return className;
    }

    /**
     * 封装debug级别日志
     *
     * @param msg
     * @param arguments
     */
    public static void Debug(String msg, Object... arguments)
    {
        if (arguments != null && arguments.length > 0)
        {
            MessageFormat temp = new MessageFormat(msg);
            msg = temp.format(arguments);
        }
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 封装debug级别日志
     *
     * @param msg
     */
    public static void debug(String msg)
    {
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, EMPTY_ARRAY, null);
    }


    /**
     * 封装info级别日志
     *
     * @param msg
     * @param arguments
     */
    public static void info(String msg, Object... arguments)
    {
        if (arguments != null && arguments.length > 0)
        {
            MessageFormat temp = new MessageFormat(msg);
            msg = temp.format(arguments);
        }
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.INFO_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 封装warn级别日志
     *
     * @param msg
     * @param arguments
     */
    public static void warn(String msg, Object... arguments)
    {
        if (arguments != null && arguments.length > 0)
        {
            MessageFormat temp = new MessageFormat(msg);
            msg = temp.format(arguments);
        }
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.WARN_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 封装warn级别日志
     *
     * @param msg
     */
    public static void warn(String msg)
    {
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.WARN_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 封装error级别日志
     *
     * @param msg
     * @param arguments
     */
    public static void error(String msg, Object... arguments)
    {
        if (arguments != null && arguments.length > 0)
        {
            MessageFormat temp = new MessageFormat(msg);
            msg = temp.format(arguments);
        }
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 封装error级别日志
     *
     * @param msg
     */
    public static void error(String msg)
    {
        getLocationAwareLogger().log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, EMPTY_ARRAY, null);
    }

    /**
     * 异常堆栈转字符串
     *
     * @param e
     * @return
     */
    public static String ExceptionToString(Exception e)
    {
        StringWriter sw = null;
        PrintWriter pw = null;
        try
        {
            if (e == null)
            {
                return "无具体异常信息";
            }
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            return sw.toString();
        } catch (Exception ex)
        {
            EnoviaLogger.error("异常堆栈转字符串异常", ex);
            return "";
        } finally
        {
            sw.flush();
            pw.flush();
            pw.close();
        }

    }

}
